/* eslint-disable @typescript-eslint/indent */
import { Ref, SetupContext, computed, defineComponent, nextTick, onMounted, ref, watch } from "vue";
import { CapsuleItem, CapsuleProps, capsuleProps } from "./capsule.props";
import FCapsuleItem from './capsule-item.component';
import './capsule.css';

export default defineComponent({
    name: 'FCapsule',
    props: capsuleProps,
    emits: ['change', 'update:modelValue'],
    setup(props: CapsuleProps, context: SetupContext) {
        const items = ref(props.items as CapsuleItem[]);
        const capsuleContainerRef = ref<any>();
        const paddingSpace = 2;
        const modelValue = ref(props.modelValue);
        const transition = ref('none');
        const capsuleColorType = ref(props.type);

        const capsuleContainerClass = computed(() => {
            const classObject = {
                'f-capsule-container': true
            } as Record<string, boolean>;
            if (capsuleColorType.value) {
                classObject[capsuleColorType.value] = true;
            }
            return classObject;
        });

        const capsuleContainerStyle = computed(() => {
            const styleObject = {
            } as Record<string, any>;
            return styleObject;
        });

        const capsuleItemClass = function (item: CapsuleItem) {
            const classObject = {
                'f-capsule-item': true,
                'f-capsule-active-item': item.value === modelValue.value
            } as Record<string, boolean>;
            return classObject;
        };

        const capusleClass = computed(() => {
            const classObject = {
                'f-capsule': true
            } as Record<string, boolean>;
            return classObject;
        });

        const capsulePostion = ref(paddingSpace);
        const capsuleWidth = ref(0);
        const capsuleBoardWidth = ref(0);

        const capsuleStyle = computed(() => {
            const styleObject = {
                'left': `${capsulePostion.value}px`,
                'width': `${capsuleWidth.value}px`,
                'transition': transition.value
            } as Record<string, any>;
            return styleObject;
        });

        const capusleBoardStyle = computed(() => {
            const styleObject = {
                'width': `${capsuleBoardWidth.value}px`
            } as Record<string, any>;
            return styleObject;
        });

        const caspuleItemRefMap = new Map<any, Ref<any>>();

        function moveCapsuleToActiveItem(item: CapsuleItem) {
            if (caspuleItemRefMap.has(item.value)) {
                const activeItemElement = caspuleItemRefMap.get(item.value)?.value as HTMLElement;
                if (activeItemElement) {
                    const activeItemRect = activeItemElement.getBoundingClientRect();
                    const hostRect = capsuleContainerRef.value.getBoundingClientRect();
                    capsulePostion.value = activeItemRect.left - hostRect.left + paddingSpace + capsuleContainerRef.value.scrollLeft;
                    capsuleWidth.value = activeItemRect.width - 2 * paddingSpace;
                }
            }
        }

        function updateActiveItem(item: CapsuleItem, emitChangeEvent?: boolean) {
            const capsuleItemValue = item.value;
            modelValue.value = capsuleItemValue;
            context.emit('update:modelValue', capsuleItemValue);
            moveCapsuleToActiveItem(item);
            if (emitChangeEvent) {
                context.emit('change', capsuleItemValue);
            }
        }

        function setActiveItemByValue(activeValue: any) {
            const matchedItemIndex = items.value.findIndex((item: CapsuleItem) => item.value === activeValue);
            if (matchedItemIndex > -1) {
                updateActiveItem(items.value[matchedItemIndex], false);
            }
        }

        watch(
            () => props.modelValue,
            (value: any) => {
                modelValue.value = value;
                setActiveItemByValue(modelValue.value);
            }
        );

        watch(
            () => props.items,
            async (newItems: CapsuleItem[]) => {
                items.value = newItems;
                await nextTick();
                setActiveItemByValue(modelValue.value);
                capsuleBoardWidth.value = Array.from(caspuleItemRefMap.values())
                    .reduce<number>((itemTotalWidth: number, capsuleItemRef: Ref<any>) => {
                        itemTotalWidth += capsuleItemRef.value.clientWidth;
                        return itemTotalWidth;
                    }, 0);
            }
        );

        onMounted(async () => {
            setActiveItemByValue(modelValue.value);
            await nextTick();
            transition.value = '0.1s ease-out all';
            capsuleBoardWidth.value = Array.from(caspuleItemRefMap.values())
                .reduce<number>((itemTotalWidth: number, capsuleItemRef: Ref<any>) => {
                    itemTotalWidth += capsuleItemRef.value.clientWidth;
                    return itemTotalWidth;
                }, 0);
        });

        function onClickCapsuleItem($event: MouseEvent, item: CapsuleItem) {
            updateActiveItem(item, true);
        }

        function onCapsuleItemMounted(capsuleItemRef: Ref<any>, capsuleItemValue: any) {
            caspuleItemRefMap.set(capsuleItemValue, capsuleItemRef);
        }

        function renderCapsuleItem(item: CapsuleItem, index: number) {
            return (
                <FCapsuleItem name={item.name} value={item.value} isActive={item.value === modelValue.value} index={index}
                    onMounted={onCapsuleItemMounted} onActive={onClickCapsuleItem}
                ></FCapsuleItem>
            );
        }

        return () => {
            return (
                <span ref={capsuleContainerRef} class={capsuleContainerClass.value} style={capsuleContainerStyle.value}>
                    <span class="f-capsule-pane">
                        {
                            items.value.map((item: CapsuleItem, index: number) => {
                                return renderCapsuleItem(item, index);
                            })
                        }
                    </span>
                    <small class={capusleClass.value} style={capsuleStyle.value}>
                    </small>
                    <div class="f-capsule-board" style={capusleBoardStyle.value}></div>
                </span>
            );
        };
    }
});
